package com.runa.monitor.platinterface.netservice.server;

import com.runa.monitor.platinterface.netservice.connect.Session;
import com.runa.monitor.platinterface.netservice.handler.DtuChannelInitializer;
import com.runa.protocol.enums.ModbusType;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * @author zhuj
 */
public class ListenerServer extends Server {

    private final Logger logger = LoggerFactory.getLogger(ListenerServer.class);

    private static final Map<String, ListenerServer> LISTENER = new HashMap<>();

    private int port;

    private String dtuProtocol;

    private ModbusType modbusType;

    private Map<String, Session> clientSessions = new HashMap<>();

    private EventLoopGroup workGroup = new NioEventLoopGroup();

    private EventLoopGroup bossGroup = new NioEventLoopGroup(1);

    public static ListenerServer getInstance(String dtuProtocol, ModbusType modbusType, int port) {
        String key = dtuProtocol+modbusType+port;
        ListenerServer listener;
        synchronized (ListenerServer.class) {
            listener = LISTENER.get(key);
            if (listener == null) {
                listener = new ListenerServer(dtuProtocol, modbusType, port);
                LISTENER.put(key, listener);
            }
        }
        return listener;
    }

    private ListenerServer(String dtuProtocol, ModbusType modbusType, int port) {
        this.port = port;
        this.dtuProtocol = dtuProtocol;
        this.modbusType = modbusType;
        launchListener();
    }

    private void launchListener() {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_REUSEADDR, true)
                .childHandler(new DtuChannelInitializer(dtuProtocol, modbusType, this));
        try {
            bootstrap.bind(port).sync();
            logger.info("Listener Protocol: {} start, listen port: {}",dtuProtocol, port);
        } catch (Exception e){
            logger.error("Listener start error: ", e);
        }
    }

    @Override
    public boolean shutdown() {
        try {
            if (bossGroup != null) {
                bossGroup.shutdownGracefully();
            }
            if (workGroup != null) {
                workGroup.shutdownGracefully();
            }
        } catch (Exception e) {
            logger.error("Listener Protocol: {} close Error!", dtuProtocol);
            return false;
        }
        LISTENER.remove(this.dtuProtocol+this.modbusType+this.port);
        logger.info("Listener Protocol: {} close, listen port: {}",dtuProtocol, port);
        return true;
    }

    @Override
    public void reConnect(Session oldSession) {
    }

    public void setClientSession(String clientId, Session session) {
        clientSessions.put(clientId, session);
    }

    public Session getClientSession(String clientId) {
        return clientSessions.get(clientId);
    }
}
